#include "MultiBody.h"

default_random_engine e((unsigned)time(0));//随机数引擎

int int_rand(int min, int max)
{
	uniform_int_distribution<> u(min, max);
	return u(e);
}
double double_rand(double min, double max)
{
	uniform_real_distribution<double> u(min, max);
	return u(e);
}

MultiBody::MultiBody()
{
	bodies.cbegin() = bodies.cend();
	bodies_num= 0;
}
MultiBody::MultiBody(int num)
{
	bodies_num = num;
	for (int i = 1; i <= bodies_num; ++i)
	{
		bodies.push_back( new Body(
			int_rand(300, 700),
			int_rand(-800, 800),
			int_rand(-430, 430),
			double_rand(-20.0, 20.0),
			double_rand(-20.0, 20.0),
			RGB(int_rand(0, 256), int_rand(0, 256), int_rand(0, 256)),
			i));//放入随机天体
	}
	bodies.push_front(new Body(30000,0,0,0.0,0.0,
			RGB(int_rand(0, 256), int_rand(0, 256), int_rand(0, 256)),
			0));
	(* bodies.begin())->set_Lock(1);//放入主天体，并锁定
}
MultiBody::~MultiBody()
{
	
	for (auto body : bodies)
		if (body != nullptr)
		{
			delete body;
			body = nullptr;
		}
}

Vector_2D MultiBody::get_vec_dis(const Body* obj1, const Body* obj2)
{
	return obj2->pos-obj1->pos;
}
double MultiBody::get_dis(const Body* obj1, const Body* obj2)
{
	Vector_2D vec_dis = get_vec_dis(obj1, obj2);
	return vec_dis.get_len();
}

Body* MultiBody::hit_check(Body* obj1, Body* obj2)
{
	if ((obj1 != obj2)&&(obj1->m!=0)&&(obj2->m!=0))
	{
		double distance = get_dis(obj1, obj2);
		if (distance <= obj1->r + obj2->r)
		{
			if (obj1->m >= obj2->m)
			{
				//动量公式m1v1 + m2v2 = (m1+m2)v
				obj1->v = (obj1->v * (obj1->m) + obj2->v * (obj2->m)) /
					((obj1->m) + (obj2->m));

				//碰撞后质量相加
				obj1->m += obj2->m;
				obj1->cal_r();

				return obj2;  //返回撞击后质量小的天体的指针
			}
			else
			{
				//动量公式m1v1 + m2v2 = (m1+m2)v
				obj2->v = (obj1->v * (obj1->m) + obj2->v * (obj2->m)) / 
					((obj1->m) + (obj2->m));

				//碰撞后质量相加
				obj2->m += obj1->m;
				obj2->cal_r();

				return obj1;  //返回撞击后质量小的天体的指针
			}
		}
	}
	return nullptr;        //不发生碰撞则返回空指针
}
void MultiBody::hit_event()
{
	for (auto curr : bodies)
	{
		Body* destroyed = nullptr;
		for (auto next : bodies)
		{
			if (curr->num <= next->num || curr->m == 0 || next->m == 0)
				continue;
			else
			{
				destroyed = hit_check(curr,next);
				if (destroyed != nullptr)
					destroyed->m = 0;
			}
		}
	}
}

void MultiBody::inter_F(Body* obj1, Body* obj2)
{
	if (obj1 != obj2)
	{
		Vector_2D d1 = get_vec_dis(obj1, obj2);
		double d1_len=d1.get_len();
		Vector_2D F1 = d1*((G * obj1->m * obj2->m) / pow(d1_len, 3)) ;

		Vector_2D d2 = get_vec_dis(obj2, obj1);
		double d2_len = d2.get_len();
		Vector_2D F2 = d2 * ((G * obj1->m * obj2->m) / pow(d2_len, 3));

		obj1->F += F1;
		obj2->F += F2;
	}
}
void MultiBody::sum_F()
{
	for (auto curr : bodies) {
		//外循环
		for (auto next : bodies) {
		//内循环
			if (next->num <= curr->num)//防止重复计算
				continue;
			else
				inter_F(curr, next);
		}
	}
}

void MultiBody::update()
{
	hit_event();
	
	for (auto body : bodies)
	{
		body->show();
		body->move();
	}
}

Body* MultiBody::find_body(int id)
{
	for (auto it : bodies)
	{
		if (it->num == id)
			return it;
	}
}